/*
 * Copyright 2010 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.websocket;

import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;

/**
 * Maintains a map of registered extensions.
 * 
 * TODO: avoid static state for mockability.
 */
public class ExtensionRegistry {

  private static final Object lock = new Object[0];

  private static final Map<Class<? extends Extension>, Extension> classMap = new IdentityHashMap<Class<? extends Extension>, Extension>();

  private static final Map<Integer, Extension> idMap = new HashMap<Integer, Extension>();

  private static final Map<Integer, Extension> opcodeMap = new HashMap<Integer, Extension>();

  @SuppressWarnings("unchecked")
  public static <T extends Extension> T findExtensionByClass(
      Class<? extends Extension> extensionClass) {
    synchronized (lock) {
      return (T) classMap.get(extensionClass);
    }
  }

  @SuppressWarnings("unchecked")
  public static <T extends Extension> T findExtensionByMetadataId(int id) {
    synchronized (lock) {
      return (T) idMap.get(id);
    }
  }

  @SuppressWarnings("unchecked")
  public static <T extends Extension> T findExtensionByOpcode(int opcode) {
    synchronized (lock) {
      return (T) opcodeMap.get(opcode);
    }
  }

  public static void register(Extension extension) {
    int id = extension.getId();
    synchronized (lock) {
      if (classMap.containsKey(extension.getClass())) {
        throw new IllegalStateException(extension.getClass().getCanonicalName()
            + " already registered");
      }
      classMap.put(extension.getClass(), extension);
      if (extension.usesMetadata()) {
        idMap.put(id, extension);
      } else {
        opcodeMap.put(id, extension);
      }
    }
  }
}
